﻿Imports System.Data
Imports System.IO
Imports System.Xml.Serialization
Imports System.ComponentModel

Public Class ActionClass
    Public Function MovieFormatter(ByVal MovieName As String, ByVal filterList As HashSet(Of String)) As String
        Dim filterItems As New List(Of String)
        filterItems.Add("(")
        filterItems.Add("[")
        filterItems.Add(".")
        filterItems.Add(" ")

        For Each filterItem In filterItems
            If MovieName.Contains(filterItem) Then
                Dim test As String = MovieFormatterSub(MovieName, filterItem, filterList)
                If Not test = "" Then
                    MovieName = test
                End If
            End If
        Next

        'return
        MovieFormatter = MovieName.Trim
    End Function

    Public Function MovieFormatterSub(ByVal movieName As String, ByVal filterItem As String, ByVal filterList As HashSet(Of String)) As String
        Dim movieName2 As String = ""
        'remove dots and other stuff
        For Each part As String In movieName.Split(filterItem(0))
            Dim exists As Boolean = False
            For Each item In filterList
                If part.ToLower.Contains(item.ToLower) Then exists = True
            Next
            If exists Then
                Exit For
            Else
                If movieName2 = "" Then
                    movieName2 = part
                Else
                    movieName2 = movieName2 & " " & part
                End If
            End If
        Next
        Return movieName2
    End Function

    Public Function ScanFolder(ByVal watchFolderName As String, ByVal filterList As HashSet(Of String)) As Dictionary(Of String, String)
        Dim newMovieList As New Dictionary(Of String, String)

        'check basefolder
        For Each File As String In Directory.GetFiles(watchFolderName).Where(Function(x As String) x.Substring(x.Length - 5).ToLower.Contains(".avi"))
            If Not newMovieList.ContainsKey(File.Substring(watchFolderName.Length + 1)) Then newMovieList.Add(File.Substring(watchFolderName.Length + 1), File)
        Next

        'check in folders
        For Each Dir As String In Directory.GetDirectories(watchFolderName)
            For Each Dir2 As String In Directory.GetDirectories(Dir)
                For Each Dir3 As String In Directory.GetDirectories(Dir2)
                    For Each Dir4 As String In Directory.GetDirectories(Dir3)
                        For Each File4 As String In Directory.GetFiles(Dir4).Where(Function(x As String) x.Substring(x.Length - 5).ToLower.Contains(".avi"))
                            If Not newMovieList.ContainsKey(File4.Substring(Dir4.Length + 1)) Then newMovieList.Add(File4.Substring(Dir4.Length + 1), File4)
                        Next
                    Next
                    For Each File3 As String In Directory.GetFiles(Dir3).Where(Function(x As String) x.Substring(x.Length - 5).ToLower.Contains(".avi"))
                        If Not newMovieList.ContainsKey(File3.Substring(Dir3.Length + 1)) Then newMovieList.Add(File3.Substring(Dir3.Length + 1), File3)
                    Next
                Next
                For Each File2 As String In Directory.GetFiles(Dir2).Where(Function(x As String) x.Substring(x.Length - 5).ToLower.Contains(".avi"))
                    If Not newMovieList.ContainsKey(File2.Substring(Dir2.Length + 1)) Then newMovieList.Add(File2.Substring(Dir2.Length + 1), File2)
                Next
            Next
            For Each File As String In Directory.GetFiles(Dir).Where(Function(x As String) x.Substring(x.Length - 5).ToLower.Contains(".avi"))
                If Not newMovieList.ContainsKey(File.Substring(Dir.Length + 1)) Then newMovieList.Add(File.Substring(Dir.Length + 1), File)
            Next
        Next

        ' MovieFormatter
        Dim newMovieList2 As New Dictionary(Of String, String)
        For Each movie As KeyValuePair(Of String, String) In newMovieList
            If Not newMovieList2.ContainsKey(MovieFormatter(movie.Key, filterList)) Then newMovieList2.Add(MovieFormatter(movie.Key, filterList), movie.Value)
        Next

        ' return
        ScanFolder = newMovieList2
    End Function

    Public Sub SeenMoviesChecks(ByVal Movies As BindingList(Of MovieInDB), ByVal SeenList As HashSet(Of String))
        For Each movie As MovieInDB In Movies
            If SeenList.Contains(movie.Title) Then
                movie.Seen = True
            Else
                movie.Seen = False
            End If
        Next
    End Sub

    Public Sub AddPosters(ByVal Movies As BindingList(Of MovieInDB), ByVal DataFolder As String)
        For Each Movie As MovieInDB In Movies
            If File.Exists(DataFolder & Movie.IMDBCode & ".jpg") Then
                Movie.PosterImage = New System.Drawing.Bitmap(DataFolder & Movie.IMDBCode & ".jpg")
            End If
        Next
    End Sub

    Public Sub MovieScrollLoadData(ByVal Movies As BindingList(Of MovieInDB), ByVal SeenList As HashSet(Of String), ByVal MovieScrollListView As ListView)
        For Each Movie As MovieInDB In Movies
            If Movie.PosterImage IsNot Nothing And Not SeenList.Contains(Movie.Title) Then
                Dim InMovieScrollList As New HashSet(Of String)
                For Each item As ListViewItem In MovieScrollListView.Items
                    InMovieScrollList.Add(item.ImageKey)
                Next
                If Not InMovieScrollList.Contains(Movie.Title) Then
                    MovieScrollListView.LargeImageList.Images.Add(Movie.Title, Movie.PosterImage)
                    MovieScrollListView.Items.Add(Movie.Title & " - " & Movie.Rating, Movie.Title)
                End If
            End If
        Next
        'check for deletion
        For Each item As ListViewItem In MovieScrollListView.Items
            If SeenList.Contains(item.ImageKey) Then item.Remove()
        Next
        MovieScrollListView.Sort()
    End Sub

    Public Sub RemoveDuplicates(ByVal Movies As BindingList(Of MovieInDB))
        Dim LocationList As New HashSet(Of String)
        Dim MoviesToBeDeleted As New List(Of MovieInDB)
        For Each movie As MovieInDB In Movies
            'write down locations
            If LocationList.Contains(movie.Location) Then MoviesToBeDeleted.Add(movie)
            LocationList.Add(movie.Location)
        Next
        For Each movie As MovieInDB In MoviesToBeDeleted
            'create list of movies to be deleted
            Movies.Remove(movie)
        Next
    End Sub
End Class

Public Class IMDBClass
    Dim HomePanel As Panel
    Dim AddInfoLinkLabel As New LinkLabel
    Dim TreeView1 As Windows.Forms.TreeView = Nothing
    Dim IMDBUserControl As UserControl
    Dim CloseLinkLabel As LinkLabel
    Dim SaveIMDBResult As Boolean = False
    Public MovieFound As MovieInDB
    Public MovieFromDB As MovieInDB
    Dim IMDBClass As New Imdb.Services
    Public Delegate Sub MovieParsedEventHandler(ByVal Movie As MovieInDB)
    Public Event ShowFoundMovie As MovieParsedEventHandler
    Public Delegate Sub SaveMovieEventHandler(ByVal movie As MovieInDB)
    Public Event SaveMovie As SaveMovieEventHandler
    Public Event CollapsePanel As action

    Public Sub New(ByVal IMDBSearchPanel As Panel, ByVal MovieFromD As MovieInDB)
        HomePanel = IMDBSearchPanel
        MovieFromDB = MovieFromD
        IMDBClass.FindMovie(MovieFromDB.Title)
        AddHandler IMDBClass.FoundMovies, AddressOf _Imdb_FoundMovies
        AddHandler IMDBClass.MovieParsed, AddressOf _Imdb_MovieParsed
        'load UserControl
        HomePanel.Controls.Clear()
        IMDBUserControl = New IMDBUserControl
        IMDBUserControl.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        IMDBUserControl.Width = HomePanel.Width
        HomePanel.Controls.Add(IMDBUserControl)
        TreeView1 = DirectCast(HomePanel.Controls("IMDBUserControl").Controls("TreeView1"), TreeView)
        CloseLinkLabel = DirectCast(HomePanel.Controls("IMDBUserControl").Controls("CloseLinkLabel"), LinkLabel)
        AddHandler CloseLinkLabel.Click, AddressOf CloseClass
        AddInfoLinkLabel = DirectCast(HomePanel.Controls("IMDBUserControl").Controls("AddInfoLinkLabel"), LinkLabel)
        AddHandler AddInfoLinkLabel.Click, AddressOf AddInfo_Click
    End Sub

    Private Sub _Imdb_FoundMovies_UIThread(ByVal M As Imdb.MoviesResultset)
        TreeView1.BeginUpdate()
        TreeView1.Nodes.Clear()

        Dim popTitlesNode As TreeNode = Nothing
        Dim exTitlesNode As TreeNode = Nothing

        If (M.PopularTitles IsNot Nothing) Then
            popTitlesNode = TreeView1.Nodes.Add("Popular titles")
            popTitlesNode.Nodes.AddRange(M.PopularTitles.Select(Function(X) New TreeNode With {.Text = X.Title, .Tag = X.Id}).ToArray())
            popTitlesNode.ExpandAll()
        End If

        If (M.ExactMatches IsNot Nothing) Then
            exTitlesNode = TreeView1.Nodes.Add("Exact matches")
            exTitlesNode.Nodes.AddRange(M.ExactMatches.Select(Function(X) New TreeNode() With {.Text = X.Title, .Tag = X.Id}).ToArray())
            exTitlesNode.ExpandAll()
        End If

        If (M.PartialMatches IsNot Nothing) Then
            TreeView1.Nodes.Add("Partial matches") _
                    .Nodes.AddRange(M.PartialMatches.Select(Function(X) New TreeNode() With {.Text = X.Title, .Tag = X.Id}).ToArray())
        End If
        'load movie if just 1 found FIXME
        If popTitlesNode IsNot Nothing Then
            If popTitlesNode.Nodes.Count = 1 Then
                IMDBClass.GetMovieAsync(popTitlesNode.FirstNode.Tag.ToString, False)
                SaveIMDBResult = True
            End If
        ElseIf exTitlesNode IsNot Nothing Then
            If exTitlesNode.Nodes.Count = 1 Then
                IMDBClass.GetMovieAsync(exTitlesNode.FirstNode.Tag.ToString, False)
                SaveIMDBResult = True
            End If
        End If
        AddHandler TreeView1.AfterSelect, AddressOf treeView1_AfterSelect
        TreeView1.EndUpdate()
    End Sub

    Delegate Sub FoundMoviesCallback(ByVal M As Imdb.MoviesResultset)

    Private Sub _Imdb_FoundMovies(ByVal M As Imdb.MoviesResultset)
        If (M.Any() = False) Then
            Return
        End If

        TreeView1.Invoke(New FoundMoviesCallback(AddressOf _Imdb_FoundMovies_UIThread), New Object() {M})
    End Sub

    Private Sub _Imdb_MovieParsed(ByVal movie As Imdb.Movie)
        MovieFound = New MovieInDB
        If movie IsNot Nothing Then
            MovieFound.Title = movie.Title
            MovieFound.Year = movie.Year
            MovieFound.IMDBCode = movie.Id
            If movie.Directors IsNot Nothing Then
                MovieFound.Director = movie.Directors.ElementAt(0).Name
            Else
                MovieFound.Director = Nothing
            End If
            If (movie.Genres IsNot Nothing) Then
                MovieFound.Genres = String.Join(", ", movie.Genres.ToArray())
            End If
            If (movie.Cast IsNot Nothing) Then
                Dim actors As New List(Of String)
                For Each actor As Imdb.Person In movie.Cast
                    actors.Add(actor.Name)
                Next
                MovieFound.Actors = String.Join(", ", actors.ToArray)
            End If
            MovieFound.Plot = movie.Description
            MovieFound.Rating = movie.UserRating.ToString
            MovieFound.Location = MovieFromDB.Location
            If movie.Poster IsNot Nothing Then
                MovieFound.PosterImage = movie.Poster
                Dim FileString As String = Main.DataFolder & movie.Id & ".jpg"
                If Not IO.File.Exists(FileString) Then
                    MovieFound.PosterImage.Save(FileString, System.Drawing.Imaging.ImageFormat.Jpeg)
                    MovieFound.PosterImageFile = FileString
                End If
            Else
                'delayed load poster
                download_Poster(movie.PosterUrl)
            End If
            If SaveIMDBResult Then
                MovieFromDB = MovieFound
                RaiseEvent ShowFoundMovie(MovieFromDB)
            Else
                RaiseEvent ShowFoundMovie(MovieFound)
            End If
        End If
    End Sub

    Private Sub download_Poster(ByVal imgUrl As String)
        Using Wc As New System.Net.WebClient()
            AddHandler Wc.DownloadDataCompleted, AddressOf Wc_DownloadDataCompleted
            Wc.DownloadDataAsync(New Uri(imgUrl))
        End Using
    End Sub

    Private Sub Wc_DownloadDataCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadDataCompletedEventArgs)
        ' poster found and downloaded
        RemoveHandler CType(sender, System.Net.WebClient).DownloadDataCompleted, AddressOf Wc_DownloadDataCompleted
        Dim poster As Image = System.Drawing.Image.FromStream(New System.IO.MemoryStream(e.Result))
        MovieFound.PosterImage = poster
        RaiseEvent ShowFoundMovie(MovieFound)
        If SaveIMDBResult Then SaveMovieToDB()
    End Sub

    Private Sub treeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs)
        Dim id As Integer
        If (e.Node.Tag Is Nothing) Then
            Return
        End If
        If (Integer.TryParse(e.Node.Tag.ToString(), id)) Then
            IMDBClass.GetMovieAsync(e.Node.Tag.ToString(), False) '//0499549 avatar  //0133093 matrix
        End If
    End Sub

    Private Sub AddInfo_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        SaveMovieToDB()
    End Sub

    Private Sub SaveMovieToDB()
        MovieFromDB = MovieFound
        RaiseEvent SaveMovie(MovieFound)
        HomePanel.Controls.Clear()
        RaiseEvent CollapsePanel()
        Me.Finalize()
    End Sub

    Private Sub CloseClass(ByVal sender As Object, ByVal e As EventArgs)
        'close this class
        HomePanel.Controls.Clear()
        RaiseEvent CollapsePanel()
        Me.Finalize()
    End Sub
End Class

Public Class Storage
    Public Movies As System.ComponentModel.BindingList(Of MovieInDB)
    Public WatchFolderList As List(Of String)
    Public FilterList As HashSet(Of String)
    Public SeenList As HashSet(Of String)
    Public ScanMovieTimer As Double
    Public AutoScan As Boolean

    Public Shared Function Load(ByVal file__1 As String) As Storage
        Dim folderExists As New IO.DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) _
            & "\MovieChecker")
        If Not folderExists.Exists Then folderExists.Create()
        Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Storage))
        Using stream As FileStream = File.OpenRead(file__1)
            Dim o As Object = s.Deserialize(stream)
            Return DirectCast(o, Storage)
        End Using
    End Function

    Public Sub Save(ByVal file__1 As String)
        If File.Exists(file__1) Then
            File.Delete(file__1)
        End If
        Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Storage))
        Using stream As FileStream = File.OpenWrite(file__1)
            s.Serialize(stream, Me)
        End Using
    End Sub

    Public Sub AutoFillData()
        FilterList = New HashSet(Of String)
        For counter = 1980 To Date.Now.Year
            FilterList.Add(counter.ToString)
        Next
        FilterList.Add("avi")
        FilterList.Add("dvdrip")
        FilterList.Add("unrated")
        FilterList.Add("xvid")
        FilterList.Add("ac3")
        FilterList.Add("divx")
        FilterList.Add("dvdscr")
        FilterList.Add("axxo")
        FilterList.Add("pdtv")
        FilterList.Add("hdtv")
        FilterList.Add("internal")

        WatchFolderList = New List(Of String)
        SeenList = New HashSet(Of String)
        Movies = New BindingList(Of MovieInDB)
        Dim newMovie As New MovieInDB
        newMovie.Title = "TestMovie"
        newMovie.Location = "C:\"
        Movies.Add(newMovie)
        ScanMovieTimer = 600000 '10 minutes
        AutoScan = True
    End Sub
End Class

Public Class MovieComparer
    Implements IComparer(Of MovieInDB)

    Delegate Function ComparerFunc(ByVal a As MovieInDB, ByVal b As MovieInDB) As Integer
    Public comparer As ComparerFunc

    Public Function Compare(ByVal x As MovieInDB, ByVal y As MovieInDB) As Integer Implements System.Collections.Generic.IComparer(Of MovieInDB).Compare
        Compare = comparer(x, y)
    End Function

    Public Sub New(ByVal cf As ComparerFunc)
        comparer = cf
    End Sub
End Class

Public Class MovieInDB
    Implements IComparable(Of MovieInDB)
    Private _Title As String

    Public Function CompareTo(ByVal other As MovieInDB) As Integer Implements IComparable(Of MovieInDB).CompareTo
        CompareTo = Title.CompareTo(other.Title)
    End Function

    Public Property Title() As String
        Get
            Return _Title
        End Get
        Set(ByVal value As String)
            _Title = value
        End Set
    End Property

    Private _Year As Integer
    Public Property Year() As Integer
        Get
            Return _Year
        End Get
        Set(ByVal value As Integer)
            _Year = value
        End Set
    End Property

    <XmlIgnore()> Private _seen As Boolean
    <XmlIgnore()> Public Property Seen() As Boolean
        Get
            Return _seen
        End Get
        Set(ByVal value As Boolean)
            _seen = value
        End Set
    End Property

    <XmlIgnore()> Private _PosterImage As Image
    <XmlIgnore()> Public Property PosterImage() As Image
        Get
            Return _PosterImage
        End Get
        Set(ByVal value As Image)
            _PosterImage = value
        End Set
    End Property

    Private _PosterImageFile As String
    Public Property PosterImageFile() As String
        Get
            Return _PosterImageFile
        End Get
        Set(ByVal value As String)
            _PosterImageFile = value
        End Set
    End Property

    Private _Rating As String
    Public Property Rating() As String
        Get
            Return _Rating
        End Get
        Set(ByVal value As String)
            _Rating = value
        End Set
    End Property

    Private _Genres As String
    Public Property Genres() As String
        Get
            Return _Genres
        End Get
        Set(ByVal value As String)
            _Genres = value
        End Set
    End Property

    Private _Location As String
    Public Property Location() As String
        Get
            Return _Location
        End Get
        Set(ByVal value As String)
            _Location = value
        End Set
    End Property

    Private _Actors As String
    Public Property Actors() As String
        Get
            Return _Actors
        End Get
        Set(ByVal value As String)
            _Actors = value
        End Set
    End Property

    Private _Director As String
    Public Property Director() As String
        Get
            Return _Director
        End Get
        Set(ByVal value As String)
            _Director = value
        End Set
    End Property

    Private _IMDBCode As String
    Public Property IMDBCode() As String
        Get
            Return _IMDBCode
        End Get
        Set(ByVal value As String)
            _IMDBCode = value
        End Set
    End Property

    Private _Plot As String
    Public Property Plot() As String
        Get
            Return _Plot
        End Get
        Set(ByVal value As String)
            _Plot = value
        End Set
    End Property
End Class
